#include <stdexcept>
#include <exception>
#include <vector>
#include <sqlite3.h>
#include <sqlite3mc.h>

namespace sqlite3mc{
    class DatabaseError : public std::runtime_error {
    public:
        explicit DatabaseError(const std::string& message)
            : std::runtime_error(message), code_(0) {}

        DatabaseError(int code, const std::string& message)
            : std::runtime_error(message), code_(code) {}

        DatabaseError(int code, const std::string& message, std::string sql)
            : std::runtime_error(message), code_(code), sql_(std::move(sql)) {}

        int code() const noexcept { return code_; }

        const std::string& sql() const noexcept { return sql_; }

    private:
        int code_;
        std::string sql_;
    };

    class Result{
    public:
        Result() = default;
        
        void addRow(const std::vector<std::string>& row) {
            rows_.push_back(row);
        }
        void setColumns(const std::vector<std::string>& columns) {
            columns_ = columns;
        }

        const std::vector<std::vector<std::string>>& rows() const {
            return rows_;
        }
        const std::vector<std::string>& columns() const {
            return columns_;
        }
 private:
        
        std::vector<std::vector<std::string>> rows_;
        std::vector<std::string> columns_;
    };

    class Database{
    public:
        
        Database(const std::string& filename) : db_(nullptr) {
            connect(filename);
        }
        void connect(const std::string& filename){
            if(db_ != nullptr){
                sqlite3_close(db_);
            }
            int rc = sqlite3_open(filename.c_str(), &db_);
            if (rc != SQLITE_OK) {
                throw DatabaseError(rc, "数据库连接错误");
            }
        }
        void setPassworld(const std::string& passworld) const{
            int rc = sqlite3_key(db_, passworld.c_str(), static_cast<int>(passworld.size()));
            if (rc != SQLITE_OK) {
                throw DatabaseError(rc, "设置密码错误");
            }
            
            rc = sqlite3_exec(db_, "SELECT count(*) FROM sqlite_master;", nullptr, nullptr, nullptr);
            if (rc != SQLITE_OK) {
                throw DatabaseError(rc, "密码验证错误");
            }
        }
        // 执行查询sql并返回结果
        Result executeQuery(const std::string& sql) const{
            char* errMsg = nullptr;
            Result result;
            auto callback = [](void* data, int argc, char** argv, char** azColName) -> int {
                Result* res = static_cast<Result*>(data);
                if (res->columns().empty()) {
                    std::vector<std::string> columns;
                    for (int i = 0; i < argc; i++) {
                        columns.emplace_back(azColName[i] ? azColName[i] : "NULL");
                    }
                    res->setColumns(columns);
                }
                std::vector<std::string> row;
                for (int i = 0; i < argc; i++) {
                    row.emplace_back(argv[i] ? argv[i] : "NULL");
                }
                res->addRow(row);
                return 0;
            };
            const int rc = sqlite3_exec(db_, sql.c_str(), callback, &result, &errMsg);
            if (rc != SQLITE_OK) {
                const std::string error_message = errMsg ? errMsg : "执行查询错误";
                sqlite3_free(errMsg);
                throw DatabaseError(rc, error_message, sql);
            }
            return result;
        }
        
    private:
        sqlite3* db_;
    };

}